home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
dialog
/
html.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-03
|
26KB
|
1,070 lines
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <time.h>
#include <sys/stat.h>
#include "dialog.h"
#include "diadef.h"
#include "internal.h"
#include "cmdsock.h"
#include "dialog.m"
#include "../paths.h"
#include "../userconf/userconf.h"
#include "../netconf/netconf.h"
static char *html_host = NULL;
static int html_cli; // Handle use to talk back to client
static int port;
static int target_level;
static int history_level;
static int debug;
static int html_java; // Produce HTML code or command for the java
// front end
static HTML_VARVAL *curvars;
static MENU_STATUS html_submit; // Button action to process
static int html_postdone; // Did the POST was processed
static int html_drawdone; // Insure that we draw a html page only once
static char html_popup=0;
struct LEVEL_INFO{
MENU_STATUS status;
SSTRING key;
SSTRING title;
};
static LEVEL_INFO tblevel[20];
static int level = 0;
static const char *html_getval (int lev, const char *key)
{
char bufkey[200];
sprintf (bufkey,"%d_%s",lev,key);
const char *ret = "";
if (curvars != NULL) ret = curvars->getval(bufkey);
return ret;
}
/*
Get the new value of a field
*/
const char *html_getval (const char *key)
{
return html_getval (level,key);
}
/*
Check if a button exist as a variable (the user has clicked on it)
*/
static int html_butexist (const char *key)
{
int ret = 0;
if (curvars != NULL) ret = curvars->exist(key);
return ret;
}
static void html_reset()
{
// Variable a simply never forgotten. Some primitive form
// of garbage collection in varval.c take care of too old entries
curvars = NULL;
html_postdone = 0;
html_drawdone = 0;
html_popup=0;
}
/*
Get the original value of a field
*/
const char *html_getoldval (const char *key)
{
char oldkey[100];
sprintf (oldkey,"CUR_%s",key);
return html_getval (oldkey);
}
/*
Generate a <input command to define a field
*/
void html_defvar (
const char *type,
const char *name,
const char *value,
const char *opt)
{
html_printf ("<input type=%s name=\"%d_%s\" value=\"%s\" %s>\n"
,type,level,name,value,opt);
}
void html_defvar (
const char *type,
const char *name,
int value,
const char *opt)
{
char tmp[20];
sprintf (tmp,"%d",value);
html_defvar (type,name,tmp,opt);
}
/*
Generate a <input command to define the current value of a field
*/
void html_defvarcur (
const char *name,
const char *value)
{
html_printf ("<input type=hidden name=\"%d_CUR_%s\" value=\"%s\">\n"
,level,name,value);
}
void html_defvarcur (
const char *name,
int value)
{
char tmp[20];
sprintf (tmp,"%d",value);
html_defvarcur (name,tmp);
}
static char *html_buf;
static int html_len;
static int html_maxlen;
void html_printf (const char *ctl, ...)
{
va_list list;
va_start (list,ctl);
char buf[1000];
int len = vsprintf (buf,ctl,list);
va_end (list);
if (html_len + len > html_maxlen){
html_maxlen += 5000;
html_buf = (char*)realloc(html_buf,html_maxlen);
}
strcpy (html_buf+html_len,buf);
html_len += len;
}
void html_flush ()
{
if (html_len > 0){
write (html_cli,html_buf,html_len);
html_len = 0;
}
}
/*
Record the host name and port number to encode in URLs
*/
void html_sethost (const char *_hostname, int _port)
{
free (html_host);
html_host = strdup(_hostname);
port = _port;
}
static char KEY_ACCEPT[]="accept";
static char KEY_DEL[]="del";
static char KEY_OK[]="ok";
static char KEY_ADD[]="add";
static char KEY_EDIT[]="edit";
static char KEY_YES[]="yes";
static char KEY_NO[]="no";
/*
Format a path to a sub-meny entry
*/
static void html_setpath_level(char *path, int upto)
{
char *pt = path;
LEVEL_INFO *ptl = tblevel;
for (int i=0; i<upto; i++,ptl++){
const char *key = KEY_OK;
if (ptl->status == MENU_DEL){
key = KEY_DEL;
}else if (ptl->status == MENU_ACCEPT){
key = KEY_ACCEPT;
}else if (ptl->status == MENU_ADD){
key = KEY_ADD;
}else if (ptl->status == MENU_EDIT){
key = KEY_EDIT;
}else if (ptl->status == MENU_YES){
key = KEY_YES;
}else if (ptl->status == MENU_NO){
key = KEY_NO;
}
pt += sprintf (pt,"%s,%s/",key,ptl->key.get());
}
*pt = '\0';
}
/*
Format a context to a sub-meny entry
*/
static void html_setcontext_level(char *path, int upto)
{
char *pt = path;
LEVEL_INFO *ptl = tblevel;
for (int i=0; i<upto; i++,ptl++){
pt += sprintf (pt,"%s/",ptl->key.get());
}
*pt = '\0';
}
/*
Format a path to a sub-meny entry
*/
static void html_setpath(char *path)
{
html_setpath_level (path,level);
}
/*
Set a url pointing to a sub-menu entry
*/
void html_setaref (
const char *key, // Key for the url (path indeed)
const char *text) // Highlit text
{
char path[PATH_MAX];
html_setpath (path);
html_printf ("<A HREF=\"http://%s:%d/html:/%sok,%s\">%s</A>"
,html_host,port,path,key,text);
}
/*
Format a message suitable as a path component of a URL.
Space are transformed to ==.
*/
void html_formatkey (char *key, const char *ctl, ...)
{
va_list list;
va_start (list,ctl);
char buf[1000];
vsprintf (buf,ctl,list);
va_end (list);
char *pt = buf;
while (*pt != '\0'){
char carac = *pt++;
if (carac == ' ' || carac == '/'){
*key++ = '=';
*key++ = '=';
}else{
*key++ = carac;
}
}
*key = '\0';
}
/*
Send the header of the html document.
*/
static void html_sendintro(
const char *content_type,
int length, // Length or -1
int expires) // How much seconds this document is expected to
// be valid
{
time_t tim = time(NULL);
html_printf ("HTTP/1.0 200 Document follows\r\n");
html_printf ("MIME-Version: 1.0\r\n");
extern char *revision;
html_printf ("Server: linuxconf/%s\r\n",revision);
char buf[200];
tim += expires;
strcpy (buf,asctime(localtime(&tim)));
strip_end (buf);
html_printf ("Date: %s\r\n",buf);
html_printf ("Content-Type: %s\r\n",content_type);
if (length != -1){
html_printf ("Content-Length: %d\r\n",length);
}
html_printf ("Expires: %s\r\n",buf);
html_printf ("Last-Modified: %s\r\n",buf);
html_printf ("\r\n");
}
static CMDSOCK *cmd = NULL;
/*
Indicate that the html page has been sent and the connection can
be closed.
*/
static void html_setdone()
{
html_drawdone = 1;
html_flush ();
if (cmd != NULL) cmd->closecli (html_cli);
}
/*
Is called when a password is needed.
The proper information is sent to the www browser requesting such
a pawwword.
The web browser will retransmit this password for the rest of
the session.
*/
void html_needpasswd()
{
html_printf ("HTTP/1.0 401 Unauthorized\r\n");
time_t tim = time(NULL);
char buf[200];
strcpy (buf,asctime(localtime(&tim)));
strip_end (buf);
html_printf ("Date: %s\r\n",buf);
extern char *revision;
html_printf ("Server: linuxconf/%s\r\n",revision);
html_printf ("WWW-Authenticate: Basic realm=\"root\"\r\n");
html_printf ("Content-type: text/html\r\n");
html_printf ("\r\n"
"<HEAD><TITLE>Authorization Required</TITLE></HEAD>\r\n"
"<BODY><H1>Authorization Required</H1>\r\n"
"This server could not verify that you\r\n"
"are authorized to access the document you\r\n"
"requested. Either you supplied the wrong\r\n"
"credentials (e.g., bad password), or your\r\n"
"browser doesn't understand how to supply\r\n"
"the credentials required.<P>\r\n"
"</BODY>\r\n"
);
html_setdone();
}
PRIVATE void DIALOG::html_draw_top()
{
html_sendintro ("text/html",-1,15);
html_printf (
"<HTML>\n"
"<HEAD>\n"
"<TITLE>%s:%s</TITLE>\n"
"</HEAD>\n"
"<BODY>\n",html_host,title.get());
for (int i=0; i<history_level; i++){
char path[PATH_MAX];
html_setpath_level (path,i);
char indent[20];
memset (indent,'.',sizeof(indent));
indent[i] = '\0';
html_printf ("<a href=\"/html:/%s\">%s%s</a>\n<br>\n"
,path
,indent
,tblevel[i].title.get());
}
if (level > 0) html_printf ("<hr>\n");
}
PRIVATE void DIALOG::html_draw_intro()
{
if (!icon.is_empty()){
html_printf ("<img src=/images:images/%s.gif>\n",icon.get());
}
if (!intro.is_empty()){
html_printf ("<PRE>%s</PRE>\n\n<hr>\n",intro.get());
}
}
PRIVATE void DIALOG::html_draw_fields()
{
int lastf = getnb();
for (int i=0; i<lastf; i++) getitem(i)->html_draw (i);
}
PRIVATE void DIALOG::html_draw_form()
{
char path[300];
html_setpath_level (path,target_level);
html_printf ("<form method=post action=/html:/%s>\n",path);
html_printf ("<CENTER>\n");
html_printf ("<TABLE border=1>\n");
if (curvars != NULL){
// Define variable for previous level
int n = curvars->getnb();
for (int i=0; i<n; i++){
const char *name = curvars->getvar(i);
if (isdigit(name[0]) && atoi(name)<level){
html_printf ("<input type=hidden name=\"%s\" value=\"%s\">\n"
,name,curvars->getval(i));
}
}
}
html_draw_fields();
html_printf ("</TABLE>\n");
html_printf ("</CENTER>\n");
buttons->html_draw ();
html_printf ("</form>\n");
}
PRIVATE void DIALOG::html_draw_end()
{
html_printf ("</BODY>\n</HTML>\n");
}
/*
Draw the complete dialog including a subdialog (error, password request)
*/
PRIVATE void DIALOG::html_draw (DIALOG *spc)
{
/* #Specification: html mode / strategy / back on our feet
Maybe this is an already visited dialog. This has been visited
along the path followed while running through tblevel[]. While
doing so, we have stamp dialog title in each level (in
DIALOG::edithtml()). We will search now to see if we can find
this dialog title in tblevel and correct target_level accordingly.
This situation happen with the following case:
#
-The user is visiting one menu
-he selects one dialog
-he fills some fields and click on the "accept" button.
-A subdialog is poped
-The user fills it
-After some sub-sub-dialogs the job is done and we are
back to the original menu.
#
All these steps have collected a longer and longer html path.
Each level of the path have captured the variable states used to
go the next. So we have a very long path, but we have to
fall on our feet again with a short path.
*/
for (int i=0; i<target_level; i++){
if (tblevel[i].title.cmp(title) ==0){
target_level = i;
level = i;
break;
}
}
html_draw_top();
if (spc != NULL){
spc->html_draw_intro();
spc->html_draw_fields();
html_printf ("<hr>\n");
}
html_draw_intro();
html_draw_form();
html_draw_end();
}
/*
Draw the complete dialog
*/
PRIVATE void DIALOG::html_draw ()
{
html_draw(NULL);
}
/*
Load all field of the dialog with the received value
and check that everything is valid
Return -1 if any error.
*/
PRIVATE int DIALOG::html_validate ()
{
int ret = 0;
int lastf = getnb();
for (int i=0; i<lastf; i++) ret |= getitem(i)->html_validate (i);
return ret;
}
PUBLIC void BUTTONS_INFO::html_draw()
{
for (int i=0; i<nb; i++){
MENU_STATUS code = tbret[i];
const char *name = "nil";
if (code == MENU_HELP){
html_printf ("<a href=\"http:/help:%s.html\">"
"<img src=/images:images/%s.gif></a>\n"
,helpfile.get()+strlen(USR_LIB_LINUXCONF)+1
,tb[i]);
}else{
if (code == MENU_CANCEL
|| code == MENU_QUIT
|| code == MENU_OK){
continue; // Those buttons are useless in html mode
}else if (code == MENU_ACCEPT){
name = KEY_ACCEPT;
}else if (code == MENU_ADD){
name = KEY_ADD;
}else if (code == MENU_SAVE){
name = "save";
}else if (code == MENU_DEL){
name = KEY_DEL;
}else if (code == MENU_EDIT){
name = KEY_EDIT;
}else if (code == MENU_YES){
name = KEY_YES;
}else if (code == MENU_NO){
name = KEY_NO;
}else{
printf ("old button\n");
#if 0
char path[PATH_MAX];
html_setpath (path);
html_printf ("<a href=\"http://%s:%d/button:%s:%s\">%s</a>\n"
,html_host
,port
,tb[i]
,path
,tb[i]);
#endif
}
html_printf ("<input type=image name=%s "
"src=/images:images/%s.gif>\n"
,name,tb[i]);
}
}
}
static DIALOG *html_postdialog;
void html_forgetdialog (DIALOG *dia)
{
if (dia == html_postdialog){
html_postdialog = NULL;
#if 0
if (!html_drawdone){
// The next time we will get in edithtml, level is still equal
// to target_level, so html_draw will be called
// providing the next page to www user. This is a hack.
// After an accept, we are back to the previous menu
target_level--;
level--;
}
#endif
}
}
/* #Specification: html mode / general strategy
Here is a basic explanation of the way linuxconf manage html page
while not being that much http/html aware.
Some fact:
#
-Linuxconf is a classical modal program. Mostly, only one dialog has
the focus at a time. Further, in linuxconf, there is generally
only one dialog at once. This is acceptable for admin tasks anyway.
-html mode work with the concept of hope. You send a page to a
user and he may click on a button one day or never. You better
not wait for it. So good for a modal program.
#
The strategy is simple. Linuxconf is always waiting at the
top level of the menu hierachy for an html request. Each request
contain a path (using /'s) allowing linuxconf to navigate
in the menu hisrarchy up to a certain "level". At this point
linuxconf simply draw the dialog or menu and ... get back
to the top level.
This behavior of always getting back is trigger by returning
MENU_ESCAPE, so each part of linuxconf must be "ESCAPE" aware, which
is good anyway.
So when we get a path, we parse it and store it in a table
and note the target_level.
Important assumption here:
All dialog with input are preceded in the hierarchy by menus.
This make sens anyway. This disable support for popup dialog
however.
So we parse and store the path and lauch linuxconf from the top
level menu. While navigating in its code, linuxconf draw menus
(not really) and wait for input (not really also). If this
menu is not of the proper level, the path information will be
used as a key to identify which menu item was choosen. A MENU_OK
is then returned and linuxconf continue to navigate further into
sub-sub-menus (In fact the exact button returned is contain
in the path). At some point, it crosses the target level.
At the target level, there is two cases:
Either this is GET or a POST. If this is a GET, we draw the dialog
and escape away to the main loop. If this is a POST, then we
load all the fields of the dialog with the values received from
the POST.
Based on some special values, we know which buttons was hit and
return appropriatly MENU_ACCEPT, MENU_ADD and so on to the
application. Three things may happen. Either there is some error
message (The application identify those with html_setpopup())
or linuxconf is happy and exited to the previous level menu (Leaving
this dialog screen) or linuxconf provide a sub-dialog asking for
more info.
Most of the logic here is controlled by the DIALOG::edithtml()
function.
*/
/*
Record that the next DIALOG object is a popup dialog (error message)
*/
void html_setpopup()
{
html_popup = 1;
}
PRIVATE MENU_STATUS DIALOG::edithtml(int &nof)
{
MENU_STATUS ret = MENU_ESCAPE;
if (!html_drawdone){
static SSTRING top_str;
static SSTRING bottom_str;
if (level == target_level){
static MENU_STATUS was_button; // Was it a POST with the
// button accept
if (curvars != NULL && !html_postdone){
//html_postdialog = this;
if (html_validate() != -1){
// Those names need not be translated
// see BUTTONS_INFO::html_draw()
if (html_butexist("ok.x")){
ret = MENU_OK;
}else if (html_butexist("accept.x")){
ret = MENU_ACCEPT;
}else if (html_butexist("add.x")){
ret = MENU_ADD;
}else if (html_butexist("edit.x")){
ret = MENU_EDIT;
}else if (html_butexist("del.x")){
ret = MENU_DEL;
}else if (html_butexist("save.x")){
ret = MENU_SAVE;
}else if (html_butexist("yes.x")){
ret = MENU_YES;
}else if (html_butexist("no.x")){
ret = MENU_NO;
}else{
if (debug) fprintf (stderr,"Invalid button\n");
ret = MENU_CANCEL;
}
was_button = ret;
html_postdone = 1;
html_draw_top();
top_str.setfrom (html_buf);
html_len = 0;
html_draw_intro();
html_draw_form();
html_draw_end();
bottom_str.setfrom(html_buf);
html_len = 0;
}else{
html_printf ("500 %s\r\n"
,MSG_U(E_MISMATCH,"dialog state mismatch"));
html_setdone();
}
}else{
if (curvars != NULL){
if (html_popup){
top_str.copy (html_buf);
html_len = strlen (html_buf);
html_draw_intro();
html_draw_fields();
bottom_str.copy (html_buf+html_len);
html_len = strlen (html_buf);
}else{
if (was_button == MENU_ACCEPT && 0){
// We have accepted so we get back to
// previous menu
target_level--;
level--;
}else{
tblevel[level].status = was_button;
target_level++;
level++;
}
html_draw();
}
}else{
html_draw();
}
html_setdone();
}
}else if (level < target_level){
LEVEL_INFO *pt = tblevel + level;
pt->title.setfrom (title);
int n = getnb();
nof = -1;
for (int i=0; i<n; i++){
char key[PATH_MAX];
getitem(i)->format_htmlkey(key,i);
printf ("Compare :%s: :%s:\n",key,pt->key.get());
if (pt->key.cmp(key)==0){
nof = i;
break;
}
}
if (nof == -1
&& pt->status == MENU_OK){
html_printf ("500 %s\r\n",MSG_U(E_IVLDURL,"Invalid URL\n"));
printf ("Et ne trouve pas %d\n",pt->status);
html_setdone();
}else{
ret = pt->status;
{
#if 0
// We have to reestablish the context at the moment
// of the original POST which has happen at this
// level in a previous session
char context[200];
html_setcontext_level(context,level);
HTML_VARVAL *lv = varval_get(context);
if (lv != NULL){
HTML_VARVAL *cur = curvars;
curvars = lv;
if (html_validate() == -1){
html_printf ("500 %s\r\n",MSG_R(E_MISMATCH));
html_setdone();
}
curvars = cur;
}
#else
printf ("Intermediate validate level %d %d\n",level,ret);
if (html_validate() == -1){
html_printf ("500 %s\r\n",MSG_R(E_MISMATCH));
html_setdone();
}
printf ("Intermediate validate level %d end\n",level);
#endif
}
}
level++;
}
}
return ret;
}
static void html_parsepath(char *pt)
{
if (debug) fprintf (stderr,"Parse path :%s:\n",pt);
int len = strlen(pt);
if (len > 0 && pt[len-1] == '/') pt[len-1] = '\0';
history_level = level = target_level = 0;
if (pt[0] == '/') pt++;
while (*pt != '\0'){
char *split = strchr (pt,'/');
if (split != NULL) *split++ = '\0';
char *comma = strchr(pt,',');
if (comma != NULL){
*comma++ = '\0';
if (comma[0] != '\0') history_level++;
}
LEVEL_INFO *ptl = &tblevel[target_level++];
ptl->key.setfrom (comma);
if (strcmp(pt,KEY_OK)==0){
ptl->status = MENU_OK;
}else if (strcmp(pt,KEY_ACCEPT)==0){
ptl->status = MENU_ACCEPT;
}else if (strcmp(pt,KEY_ADD)==0){
ptl->status = MENU_ADD;
}else if (strcmp(pt,KEY_DEL)==0){
ptl->status = MENU_DEL;
}else if (strcmp(pt,KEY_YES)==0){
ptl->status = MENU_YES;
}else if (strcmp(pt,KEY_NO)==0){
ptl->status = MENU_NO;
}else if (strcmp(pt,KEY_EDIT)==0){
ptl->status = MENU_EDIT;
}
if (split != NULL){
pt = split;
}else{
break;
}
}
}
static void html_dbglog (const char *title, const char *str)
{
FILE *f = fopen ("/tmp/li.dbg","a");
if (f != NULL){
fprintf (f,"======%s=======\n",title);
fputs (str,f);
fclose (f);
}
}
static char hextoi (char asc)
{
return isdigit(asc) ? asc - '0' : (toupper(asc) - 'A') + 10;
}
static const char *html_decode (const char *str, char *buf)
{
char *pt = buf;
while (*str != '\0' && *str != '\n'){
if (*str == '%'){
str++;
*pt++ = hextoi(*str++) * 16 + hextoi(*str++);
}else if (*str == '+'){
*pt++ = ' ';
str++;
}else{
*pt++ = *str++;
}
}
*pt = '\0';
strip_end (buf);
if (*str == '\n') str++;
return str;
}
static void html_parsevar (const char *buf)
{
{
char context[200];
html_setcontext_level(context,target_level);
curvars = new HTML_VARVAL(context);
}
while (1){
char *pt = strchr(buf,'=');
if (pt == NULL){
break;
}else{
*pt++ = '\0';
char *end = strchr(pt,'&');
if (end != NULL){
*end++ = '\0';
}
char var[200];
char val[2000];
html_decode (buf,var);
html_decode (pt,val);
curvars->add (var,val);
if (end == NULL) break;
buf = end;
}
}
}
/*
Parse a potentially completed header.
Extract the "get" command or "post" command.
Return -1 if any error.
Return 0 if the header was not completed
Return 1 if the header was completed
*/
static int html_parse (
const char *str,
char *file_request, // Will contain a file to transmit to the client
char *username, // Will hold the username
char *password, // and password provided by the browser
HELP_FILE &intro)
{
unsigned expected_length = 0;
int html_post = 0;
int ret = 0;
int get_ok = 0;
file_request[0] = '\0';
html_java = 0;
html_submit = MENU_NULL;
username[0] = '\0';
password[0] = '\0';
while (*str != '\0'){
char buf[10000];
str = html_decode (str,buf);
if (buf[0] == '\0'){
if (get_ok){
html_reset();
if (html_post){
char t[100];
sprintf (t,"expe %u, got %u\n",expected_length,strlen(str));
html_dbglog ("detail",t);
if (strlen(str) >= expected_length){
strcpy (buf,str);
html_parsevar (buf);
ret = 1;
}
break;
}else{
ret = 1;
}
}else{
ret = -1;
}
}else{
char cmd[200];
char *pt = str_copyword (cmd,buf);
strupr (cmd);
int is_get = strcmp(cmd,"GET")==0;
int is_post = strcmp(cmd,"POST")==0;
if (is_get || is_post){
pt = str_skip (pt);
char path[1000];
char parm[1000];
parm[0] = '\0';
str_copyword (path,pt);
char *ptparm = strchr(path,'?');
if (ptparm != NULL){
*ptparm++ = '\0';
strcpy (parm,ptparm);
}
if (strncmp(path,"/help:",6)==0){
strcpy (file_request,path+6);
}else if (strncmp(path,"/images:",8)==0){
strcpy (file_request,path+8);
}else if (strncmp(path,"/java:",6)==0){
html_java = 1;
html_parsepath(path+6);
}else if (strncmp(path,"/html:",6)==0){
html_parsepath(path+6);
#if 0
}else if (strncmp(path,"/button:",8)==0){
char *pt = path + 8;
// No need to make this translatable
static struct BUT_LKP{
const char *name;
MENU_STATUS but;
}tb[]={
{"add", MENU_ADD},
{"del", MENU_DEL},
{"save", MENU_ADD},
{"accept", MENU_ACCEPT},
};
BUT_LKP *ptb = tb;
for (unsigned i=0; i<sizeof(tb)/sizeof(tb[0])
; i++, ptb++){
int len = strlen(ptb->name);
if (strncmp(ptb->name,pt,len)==0
&& pt[len] == ':'){
html_parsepath(pt + len + 1);
html_submit = ptb->but;
break;
}
}
#endif
}else{
strcpy (file_request,intro.getpath()+strlen(USR_LIB_LINUXCONF)+1);
strcat (file_request,".html");
}
html_post = is_post;
get_ok = 1;
}else if (stricmp(cmd,"Content-length:")==0){
expected_length = atoi(pt);
}else if (stricmp(cmd,"Authorization:")==0){
char basic[1000];
pt = str_copyword (basic,pt);
if (stricmp(basic,"Basic")==0){
pt = str_copyword (basic,pt);
char pw[1000];
base64_decode(pw,basic);
char *ptpt = strchr(pw,':');
if (ptpt != NULL){
*ptpt++ = '\0';
strcpy (username,pw);
strcpy (password,ptpt);
}
}
}
}
}
return ret;
}
static void html_copy (const char *fname)
{
char path[PATH_MAX];
sprintf (path,"%s/%s",USR_LIB_LINUXCONF,fname);
if (debug) fprintf (stderr,"Sending :%s:\n",path);
FILE *fin = fopen (path,"r");
if (fin == NULL){
html_printf ("500 file %s not found\r\n",fname);
html_flush();
}else{
struct stat st;
int size = -1;
if (stat(path,&st)!=-1) size = st.st_size;
html_sendintro(strstr(fname,".gif")!=NULL ? "image/gif" : "text/html"
,size,4*60*60);
html_flush();
char buf[10000];
int n;
while ((n=fread(buf,1,sizeof(buf),fin))> 0){
//if (debug) fwrite (buf,1,n,stderr);
write (html_cli,buf,n);
}
html_printf ("\r\n");
html_flush();
fclose (fin);
}
}
static SSTRING *tbs[200];
/*
Get a command (A "get" indeed) from a client (Web browser).
parse this command into a path that will silently show the way
so linuxconf will silently travel to the proper menu, draw it
and quit.
Return -1 if there was some error or nothing has happen
for a long time (no more job). Nothing to do for Linuxconf.
*/
int html_get (int _debug, HELP_FILE &intro)
{
debug = _debug;
if (cmd == NULL) cmd = new CMDSOCK (debug ? port : -1);
int ret = -1;
while (1){
if (cmd->listen(600*1000000) <= 0){
break;
}else{
char buf[1000];
int nb;
int cli;
if ((nb=cmd->readnext (buf,sizeof(buf)-1,cli))>=0){
if (nb == 0){
cmd->closecli (cli);
}else if (tbs[cli] == NULL
&& html_access_check(cli)!=0){
html_cli = cli;
html_printf ("500 access denied\r\n");
html_flush();
cmd->closecli (cli);
}else{
buf[nb] = '\0';
if (tbs[cli] == NULL){
tbs[cli] = new SSTRING;
}
tbs[cli]->append (buf);
if (tbs[cli]->getlen()>10000){
/* #Specification: html mode / input overflow
If linuxconf receive an http request exceding
10000 bytes, it is silently flushed.
*/
cmd->closecli(cli);
delete tbs[cli];
tbs[cli] = NULL;
}else{
char file_request[PATH_MAX];
char username[50];
char password[50];
html_dbglog ("so far",tbs[cli]->get());
int ok = html_parse (tbs[cli]->get(),file_request
,username,password,intro);
perm_setaccess(username,password);
if (ok == -1){
cmd->closecli (cli);
delete tbs[cli];
tbs[cli] = NULL;
}else if (ok > 0){
html_cli = cli;
delete tbs[cli];
tbs[cli] = NULL;
if (file_request[0] != '\0'){
html_copy (file_request);
cmd->closecli (cli);
}else{
ret = 0;
break;
}
}
}
}
}
}
}
return ret;
}